home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Libraries / UObject.Globals.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  26.8 KB  |  1,086 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UObject.inc1.p }
  4. { Copyright © 1984-1990 by Apple Computer, Inc.  All rights reserved. }
  5.  
  6. {$IFC UNDEFINED qMacApp}
  7. {$SETC qMacApp := FALSE}
  8. {$ENDC}
  9.  
  10. {$Push} {$IFC NOT qDebugTheDebugger}
  11. {$W+}
  12. {$R-}
  13. {$Init-}
  14. {$OV-}
  15. {$ENDC}
  16.  
  17. {$%+  Enable '%' in identifiers}
  18.  
  19. {=====
  20.  NOTE:
  21.  The optimizer redirects the following procedure names
  22.  We call the optimized names here since non-optimized dispatch
  23.  is not supported.
  24.  
  25. %_INITOBJ  becomes %_OPTINITOBJ
  26. %_INOBJ  becomes   %_OPTINOBJ
  27. %_SETCLASSINDEX   becomes %_OPTSETCI
  28. %_METHOD becomes   %_JMPTOTRAP
  29. }
  30.  
  31. {--------------------------------------------------------------------------------------------------}
  32.  
  33. TYPE
  34.  
  35.     ClassIdTableHandle    = ^ClassIdTablePtr;
  36.     ClassIdTablePtr     = ^ClassIdTable;
  37.     ClassIdTable        = ARRAY [1..16000] OF ObjClassId; { Actually variable size }
  38.  
  39. {--------------------------------------------------------------------------------------------------}
  40.  
  41. VAR
  42.     pMethDispAddr:        ProcPtr;                        {address of method dispatcher}
  43.     pNoOfOrderedClasses: INTEGER;
  44.     pOrderedClassIds:    ClassIdTableHandle;
  45.     pTObjectClassID:    ObjClassId;                     {ClassID of the Root class}
  46.  
  47.     pAddNewObjectsToInspector: BOOLEAN;
  48.     {$Push} {$Z+}
  49.     pDisciplineMethodCalls: BOOLEAN;                    { Discipline method calls }
  50.     pSuperClassTable:    Handle;                         {handle to superclass table}
  51.     pDispatchErrorProc: ProcPtr;                        {Routine to handle dispatching failures}
  52.     {$Pop}
  53.     pInspectLinePos:    INTEGER;                        { Used to do line breaks when inspecting
  54.                                                          fields. }
  55.     pODFail:            ProcPtr;                        {address OD Failure Handler}
  56.     pAllocateObjectsFromPerm: BOOLEAN;                    { Used to track whether to allocate objects
  57.                                                          from permanent memory or not. }
  58.  
  59. {--------------------------------------------------------------------------------------------------}
  60.  
  61. PROCEDURE OrderClassIdsByName;
  62.     FORWARD;
  63.  
  64. FUNCTION IsClassIDMemberClass(testClass: ObjClassId;
  65.                               superClass: ObjClassId): BOOLEAN;
  66.     EXTERNAL;
  67.  
  68. PROCEDURE %_NewMethod;
  69.     EXTERNAL;
  70. { Defined in UObject.a }
  71.  
  72. PROCEDURE %_CLASSINFO;
  73.     EXTERNAL;
  74. { Created by linker }
  75.  
  76. PROCEDURE %_JMPTOTRAP;
  77.     EXTERNAL;
  78. { Defined in UObject.a }
  79.  
  80. PROCEDURE %_DISCIPLINEDISPATCH;
  81.     EXTERNAL;
  82. { Defined in UObject.a }
  83.  
  84. PROCEDURE %_DISCIPLINEDISPATCH_PATCHPOINT;
  85.     EXTERNAL;
  86. { Defined in UObject.a }
  87.  
  88. PROCEDURE AddObjectToInspector(theObject: TObject);
  89.     EXTERNAL;
  90. { Defined in UInspector.p }
  91.  
  92. PROCEDURE RemoveObjectFromInspector(theObject: TObject);
  93.     EXTERNAL;
  94. { Defined in UInspector.p }
  95.  
  96. PROCEDURE %_ObjError;
  97.     FORWARD;
  98.  
  99. PROCEDURE InstallDispatcher;
  100.     FORWARD;
  101. {--------------------------------------------------------------------------------------------------}
  102. {$S MAObjectRes}
  103. {$Push} {$IFC qTrace} {$D++} {$ENDC}
  104.  
  105. FUNCTION AddNewObjectsToInspector(add: BOOLEAN): BOOLEAN;
  106.  
  107.     BEGIN
  108.     AddNewObjectsToInspector := pAddNewObjectsToInspector;
  109.     pAddNewObjectsToInspector := add;
  110.     END;
  111. {$Pop}
  112.  
  113. {--------------------------------------------------------------------------------------------------}
  114. {$S MAObjectRes}
  115.  
  116. FUNCTION AllocateObjectsFromPerm(allocateFromPerm: BOOLEAN): BOOLEAN;
  117.  
  118.     BEGIN
  119.     AllocateObjectsFromPerm := pAllocateObjectsFromPerm;
  120.     pAllocateObjectsFromPerm := allocateFromPerm;
  121.     END;
  122.  
  123. {--------------------------------------------------------------------------------------------------}
  124. {$S MAObjectRes}
  125.  
  126. FUNCTION DisciplineMethodCalls(discipline: BOOLEAN): BOOLEAN;
  127.  
  128.     BEGIN
  129.     DisciplineMethodCalls := pDisciplineMethodCalls;
  130.     pDisciplineMethodCalls := discipline;
  131.     END;
  132.  
  133. {--------------------------------------------------------------------------------------------------}
  134. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  135. {$S MAObjectRes}
  136.  
  137. PROCEDURE EachClassDo(PROCEDURE DoToClass(theClass: ObjClassId));
  138.  
  139.     VAR
  140.         tableSize:            INTEGER;
  141.         tableOffset:        INTEGER;
  142.  
  143.     BEGIN
  144.     tableSize := IntegerHandle(pSuperClassTable)^^;
  145.     tableOffset := sizeof(INTEGER);
  146.     WHILE (tableOffset < tableSize) DO
  147.         BEGIN
  148.         DoToClass(ObjClassId(tableOffset));
  149.         tableOffset := tableOffset + sizeof(ObjClassId);
  150.         END;
  151.     END;
  152. {$Pop}
  153.  
  154. {--------------------------------------------------------------------------------------------------}
  155. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  156. {$S MAObjectRes}
  157.  
  158. PROCEDURE EachSubClassDo(testClass: ObjClassId;
  159.                          PROCEDURE DoToClass(theClass: ObjClassId));
  160.  
  161.     PROCEDURE DoToCandidateClass(theClass: ObjClassId);
  162.  
  163.         BEGIN
  164.         IF (theClass <> testClass) & IsClassIDMemberClass(theClass, testClass) THEN
  165.             DoToClass(theClass);
  166.         END;
  167.  
  168.     BEGIN
  169.     EachClassDo(DoToCandidateClass);
  170.     END;
  171. {$Pop}
  172.  
  173. {--------------------------------------------------------------------------------------------------}
  174. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  175. {$S MAObjectRes}
  176.  
  177. PROCEDURE EachSuperClassDo(testClass: ObjClassId;
  178.                            PROCEDURE DoToClass(theClass: ObjClassId));
  179.  
  180.     VAR
  181.         theSuperClass:        ObjClassId;
  182.  
  183.     BEGIN
  184.     theSuperClass := GetSuperClassID(testClass);
  185.     WHILE theSuperClass <> kNilClass DO
  186.         BEGIN
  187.         DoToClass(theSuperClass);
  188.         theSuperClass := GetSuperClassID(theSuperClass);
  189.         END;
  190.     END;
  191. {$Pop}
  192.  
  193. {--------------------------------------------------------------------------------------------------}
  194. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  195. {$S MAObjectRes}
  196.  
  197. PROCEDURE FailNonObject(obj: UNIV TObject);
  198.  
  199.     BEGIN
  200.     IF NOT IsObject(obj) THEN
  201.         BEGIN
  202.         {$IFC qDebug}
  203.         IF VerboseIsObject(obj) THEN;                    { show why }
  204.         WrLblHexLongint('Object that failed discipline', ord(obj));
  205.         WriteLn;
  206.         ProgramBreak('');
  207.         {$ENDC}
  208.         Failure(minErr, 0);                             { ??? need to assign a message }
  209.         END;
  210.     END;
  211. {$Pop}
  212.  
  213. {--------------------------------------------------------------------------------------------------}
  214. {$S MAObjectRes}
  215. {$Push} {$IFC qTrace} {$D++} {$ENDC}
  216.  
  217. PROCEDURE FreeIfObject(obj: TObject);
  218.  
  219.     BEGIN
  220.     IF obj <> NIL THEN
  221.         BEGIN
  222.         {$IFC qDebug}
  223.         IF NOT VerboseIsObject(obj) THEN
  224.             ProgramBreak('In FreeIfObject: Not handed a valid object.');
  225.         {$ENDC}
  226.         obj.Free;
  227.         END;
  228.     END;
  229. {$Pop}
  230.  
  231. {--------------------------------------------------------------------------------------------------}
  232. {$S MAObjectRes}
  233. {$Push} {$IFC qTrace} {$D++} {$ENDC}
  234.  
  235. PROCEDURE FreeObject(obj: TObject);
  236.  
  237.     BEGIN
  238.     FreeIfObject(obj);
  239.     END;
  240. {$Pop}
  241.  
  242. {--------------------------------------------------------------------------------------------------}
  243. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  244. {$S MAObjectRes}
  245.  
  246. FUNCTION GetClassID(obj: TObject): ObjClassId;
  247.  
  248.     BEGIN
  249.     {$Ifc qDebug}
  250.     FailNonObject(obj);
  251.     {$Endc}
  252.     GetClassID := ObjClassId(IntegerHandle(obj)^^);
  253.     END;
  254. {$Pop}
  255.  
  256. {--------------------------------------------------------------------------------------------------}
  257. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  258. {$W+}
  259. {$R-}
  260. {$OV-}
  261. {$S MAObjectRes}
  262.  
  263. FUNCTION GetClassIDFromName(clName: MAName): ObjClassId;
  264.  
  265.     VAR
  266.         high, low, index:    INTEGER;
  267.         nameFromTable:        MAName;
  268.         compareResult:        INTEGER;
  269.         id:                 INTEGER;
  270.  
  271.     BEGIN
  272.     UprMAName(clName);
  273.     IF pNoOfOrderedClasses > 0 THEN
  274.         BEGIN
  275.         low := 1;
  276.         high := pNoOfOrderedClasses;
  277.         REPEAT
  278.             index := BSR(low + high, 1);                { (low + high) DIV 2 }
  279.             id := pOrderedClassIds^^[index];
  280.             GetClassNameFromID(id, nameFromTable);
  281.             compareResult := CompareStrings(clName, nameFromTable);
  282.             IF compareResult = 0 THEN
  283.                 BEGIN
  284.                 GetClassIDFromName := id;
  285.                 EXIT(GetClassIDFromName);
  286.                 END;
  287.             IF compareResult < 0 THEN
  288.                 high := index - 1
  289.             ELSE
  290.                 low := index + 1;
  291.         UNTIL low > high;
  292.         END;
  293.  
  294.     {$IFC qDebug}
  295.     ProgramBreak(Concat('Can''t find class name ', clName));
  296.     {$ENDC qDebug}
  297.     GetClassIDFromName := kNilClass;
  298.     END;
  299. {$Pop}
  300.  
  301. {--------------------------------------------------------------------------------------------------}
  302. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  303. {$W+}
  304. {$R-}
  305. {$OV-}
  306. {$S MAObjectRes}
  307.  
  308. PROCEDURE GetClassNameFromID(classID: ObjClassId;
  309.                              VAR clName: MAName);
  310.  
  311.     CONST
  312.         kClasInfoPrefix     = 'CLASINFO.';                { 'CLASINFO.' prepended to class name }
  313.  
  314.     VAR
  315.         namePtr:            Ptr;
  316.         discard:            StringPtr;
  317.         nameLength:         INTEGER;
  318.         clNamePtr:            Ptr;
  319.         i:                    INTEGER;
  320.  
  321.     BEGIN
  322.     IF (classID = kNilClass) | ODD(classID) THEN
  323.         clName := kInvalidObj
  324.     ELSE
  325.         BEGIN
  326.         namePtr := Ptr(LongIntPtr(IntegerPtr(ord(pSuperClassTable^) + IntegerHandle(pSuperClassTable
  327.                                              )^^ + classID)^ + ord(GetA5) + 2)^ + 4);
  328.  
  329.         { discard := validMacsBugSymbol(namePtr, ord(namePtr) + 256, @clName); }
  330.         { delete(clName, 1, 9); }                        { 'CLASINFO.' }
  331.     {!!! the above function call could conceivably return a null terminated pascal string
  332.     that would exceed a Str255 by one byte.  If that happens we're HOSED.  The workaround
  333.     is to have the validMacsBugSymbol call put the returned string on the stack with room
  334.     for that last null byte.  The cost is yet another copy of the string on the stack. So…
  335.     anticipating that no identifier names will ever ACTUALLY be 255 chars we take the simple
  336.     path and return the name directly into the var parameter. }
  337.  
  338.         { We need all the speed we can get here, so forego the use of validMacsBugSymbol
  339.           (it did make a difference) and do it ourselves.  This routine would be a good
  340.           candidate for assembly }
  341.  
  342.         IF namePtr^ = $FF80 THEN                        { $FF80 instead of $80 as compile word
  343.                                                          extends }
  344.             BEGIN
  345.             namePtr := Ptr(ord(namePtr) + 1);
  346.             nameLength := namePtr^ - Length(kClasInfoPrefix);
  347.             END
  348.         ELSE
  349.             nameLength := BAND(namePtr^, $7F) - Length(kClasInfoPrefix);
  350.         clName[0] := CHR(Min(kMANameSize, nameLength));
  351.         clNamePtr := Ptr(ord(@clName) + 1);
  352.         namePtr := Ptr(ord(namePtr) + Length(kClasInfoPrefix) + 1);
  353.         FOR i := 1 TO ord(clName[0]) DO
  354.             BEGIN
  355.             clNamePtr^ := namePtr^;
  356.             clNamePtr := Ptr(ord(clNamePtr) + 1);
  357.             namePtr := Ptr(ord(namePtr) + 1);
  358.             END;
  359.  
  360.         END;
  361.     END;
  362. {$Pop}
  363.  
  364. {--------------------------------------------------------------------------------------------------}
  365. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  366. {$S MAObjectRes}
  367.  
  368. FUNCTION GetClassSizeFromId(classID: ObjClassId): Size;
  369.  
  370.     BEGIN
  371.     GetClassSizeFromId := IntegerPtr(LongIntPtr(IntegerPtr(ord(pSuperClassTable^) +
  372.                                                            IntegerHandle(pSuperClassTable)^^ +
  373.                                                            classID)^ + ord(GetA5) + 2)^ +
  374.                           2)^;
  375.  
  376.     END;
  377. {$Pop}
  378.  
  379. {--------------------------------------------------------------------------------------------------}
  380. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  381. {$W+}
  382. {$R-}
  383. {$OV-}
  384. {$S MAObjectRes}
  385.  
  386. FUNCTION GetSuperClassID(objID: ObjClassId): ObjClassId;
  387.  
  388.     BEGIN
  389.     IF objID <> kNilClass THEN
  390.         GetSuperClassID := ObjClassIDPtr(ord(pSuperClassTable^) + objID)^
  391.     ELSE
  392.         GetSuperClassID := kNilClass;
  393.     END;
  394. {$Pop}
  395.  
  396. {--------------------------------------------------------------------------------------------------}
  397. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  398. {$S MADebug}
  399.  
  400. PROCEDURE IDUobject;
  401.  
  402.     BEGIN
  403.     WRITELN('Uobject of 14 Feb 90 (Valentine''s Day), Compiled on ', COMPDATE, ' @ ', COMPTIME);
  404.     END;
  405. {$Pop}
  406.  
  407. {--------------------------------------------------------------------------------------------------}
  408. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  409. {$S MAObjectRes}
  410.  
  411. FUNCTION GetSuperClassTableHandle: Handle;
  412.  
  413.     BEGIN
  414.     {$Push} {$B-}                                        { Force Jump Table relative }
  415.     GetSuperClassTableHandle := Handle(ord(@%_CLASSINFO) + 2); { skip jmp instruction to make PHONY
  416.                                                                 handle }
  417.     {$Pop}
  418.     END;
  419. {$Pop}
  420.  
  421. {--------------------------------------------------------------------------------------------------}
  422. {$S MAInit}
  423.  
  424. PROCEDURE InitUObject;
  425.  
  426.     BEGIN
  427.     {$IFC qInspector}
  428.     pAddNewObjectsToInspector := TRUE;
  429.     {$EndC}
  430.     {$IFC qDebug}
  431.     pDisciplineMethodCalls := TRUE;
  432.     {$ENDC qDebug}
  433.  
  434.     pAllocateObjectsFromPerm := TRUE;
  435.  
  436.     InstallDispatcher;
  437.  
  438.     OrderClassIdsByName;
  439.     pTObjectClassID := GetClassIDFromName('TObject');
  440.     END;
  441.  
  442. {--------------------------------------------------------------------------------------------------}
  443. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  444. {$S MADebug}
  445.  
  446. PROCEDURE InspectField(fieldName: Str255;
  447.                        fieldAddr: Ptr;
  448.                        fieldType: INTEGER);
  449.  
  450.     VAR
  451.         s:                    Str255;
  452.         x:                    INTEGER;
  453.  
  454.     BEGIN
  455.     IF fieldType <> bClass THEN
  456.         BEGIN
  457.         FieldToString(fieldAddr, fieldType, s);
  458.         x := Length(fieldName) + 1 + Length(s);
  459.         {??? maybe a better solution would be to let the transcript do it's own word breaks}
  460.         {$IFC qDebug}
  461.         IF pInspectLinePos + x + 2 >= DebugTranscriptWidth THEN
  462.             BEGIN
  463.             WriteLn;
  464.             pInspectLinePos := 0;
  465.             END
  466.         ELSE IF pInspectLinePos <> 0 THEN                { If not at the start of a line }
  467.             BEGIN
  468.             WRITE('  ');
  469.             pInspectLinePos := pInspectLinePos + 2;
  470.             END;
  471.         {$EndC}
  472.         WRITE(fieldName, '=', s);
  473.         pInspectLinePos := pInspectLinePos + x;
  474.         END;
  475.     END;
  476. {$Pop}
  477.  
  478. {--------------------------------------------------------------------------------------------------}
  479. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  480. {$W+}
  481. {$R-}
  482. {$OV-}
  483. {$S MADebug}
  484.  
  485. PROCEDURE InspectObject(obj: TObject);
  486.  
  487.     VAR
  488.         oldState:            BOOLEAN;
  489.  
  490.     BEGIN
  491.     IF VerboseIsObject(obj) THEN
  492.         BEGIN
  493.         oldState := obj.Lock(TRUE);
  494.         obj.Inspect;
  495.         WriteLn;
  496.         oldState := obj.Lock(oldState);
  497.         END
  498.     ELSE
  499.         BEGIN
  500.         WritePtr(obj);
  501.         WriteLn(' is not a TObject!');
  502.         END;
  503.     END;
  504. {$Pop}
  505.  
  506. {--------------------------------------------------------------------------------------------------}
  507.  
  508. FUNCTION IsObject(obj: UNIV TObject): BOOLEAN;
  509. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  510. {$W+}
  511. {$R-}
  512. {$OV-}
  513. {$S MAObjectRes}
  514.  
  515.     BEGIN
  516.  
  517.     IF IsHandle(obj)
  518.     { Test for handle not purged since we don't allow purgeable objects (??? yet?, ever?) }
  519.        & (Ptr(StripLong(Handle(obj)^)) <> NIL)
  520.     { Test objecthood }
  521.        & IsClassIDMemberClass(ObjClassIDHandle(obj)^^, pTObjectClassID) &
  522.        (GetHandleSize(Handle(obj)) >= GetClassSizeFromId(ObjClassIDHandle(obj)^^)) THEN
  523.         IsObject := TRUE
  524.     ELSE
  525.         IsObject := FALSE;
  526.     END;
  527. {$Pop}
  528.  
  529. {--------------------------------------------------------------------------------------------------}
  530. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  531. {$W+}
  532. {$R-}
  533. {$OV-}
  534. {$S MAObjectRes}
  535.  
  536. FUNCTION IsMemberClassID(obj: TObject;
  537.                          objID: ObjClassId): BOOLEAN;
  538.  
  539.     BEGIN
  540.     {$IFC qDebug}
  541.     FailNonObject(obj);
  542.     {$ENDC}
  543.     IF IsObject(obj) THEN
  544.         IsMemberClassID := IsClassIDMemberClass(ObjClassIDHandle(obj)^^, objID)
  545.     ELSE
  546.         IsMemberClassID := FALSE;
  547.     END;
  548. {$Pop}
  549.  
  550. {--------------------------------------------------------------------------------------------------}
  551. {$S MAObjectRes}
  552. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  553.  
  554. FUNCTION MakeNewInstance(classID: ObjClassId): TObject;
  555. { makes objects for "new" calls.  Internal use only. }
  556.  
  557. {$IFC qDebug}
  558.  
  559.     CONST
  560.         initVal             = $F1F1;                    { guaranteed to be odd at all byte
  561.                                                          boundaries }
  562.         {$ENDC}
  563.  
  564.     VAR
  565.         {$IFC qDebug}
  566.         i:                    Size;
  567.         p:                    IntegerPtr;
  568.         {$ENDC}
  569.  
  570.         itsSize:            Size;
  571.         obj:                TObject;
  572.  
  573.     BEGIN
  574.     IF classID <> kNilClass THEN
  575.         BEGIN
  576.         itsSize := GetClassSizeFromId(classID);
  577.         IF qMacApp & pAllocateObjectsFromPerm THEN
  578.             Handle(obj) := NewPermHandle(itsSize)
  579.         ELSE
  580.             Handle(obj) := NewHandle(itsSize);
  581.  
  582.         IF obj <> NIL THEN
  583.             BEGIN
  584.  
  585.             {$IFC qDebug}
  586.             {Initialize the object to $F1F1F1F1...}
  587.             p := IntegerPtr(Handle(obj)^);
  588.             FOR i := 1 TO itsSize DIV 2 DO
  589.                 BEGIN
  590.                 p^ := initVal;
  591.                 p := IntegerPtr(ord(p) + 2);
  592.                 END;
  593.             {$ENDC}
  594.  
  595.             { Install class ID into object }
  596.             ObjClassIDHandle(obj)^^ := classID;
  597.  
  598.             {$IFC qInspector}
  599.             IF pAddNewObjectsToInspector THEN
  600.                 AddObjectToInspector(obj);
  601.             {$ENDC}
  602.             END;
  603.         MakeNewInstance := obj;
  604.         END
  605.     ELSE
  606.         MakeNewInstance := NIL;
  607.     END;
  608. {$Pop}
  609.  
  610. {--------------------------------------------------------------------------------------------------}
  611. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  612. {$W+}
  613. {$R-}
  614. {$OV-}
  615. {$S MAObjectRes}
  616.  
  617. FUNCTION NewObjectByClassId(classID: ObjClassId): TObject;
  618.  
  619. {$IFC qDebug}
  620.  
  621.     VAR
  622.         s:                    MAName;
  623.         className:            MAName;
  624.         {$ENDC}
  625.  
  626.     BEGIN
  627.     {$IFC qDebug}
  628.     IF gAskAboutAlloc & CanReadLn THEN
  629.         BEGIN
  630.  
  631.         GetCallersMethodName(s);
  632.         GetClassNameFromID(classID, className);
  633.         WriteLn('Within ', s, ', trying to make a ''', className, '''.');
  634.  
  635.         IF ReadYesNo('     Return NIL (Y or N) [N]? ') THEN
  636.             BEGIN
  637.             NewObjectByClassId := NIL;
  638.             EXIT(NewObjectByClassId);
  639.             END;
  640.         END;
  641.     {$ENDC qDebug}
  642.  
  643.     NewObjectByClassId := MakeNewInstance(classID);
  644.     END;
  645. {$Pop}
  646.  
  647. {--------------------------------------------------------------------------------------------------}
  648. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  649. {$W+}
  650. {$R-}
  651. {$OV-}
  652. {$S MAObjectRes}
  653.  
  654. FUNCTION NewObjectByClassName(className: MAName): TObject;
  655.  
  656.     VAR
  657.         classID:            ObjClassId;
  658.         {$IFC qDebug}
  659.         s:                    MAName;
  660.         {$ENDC}
  661.  
  662.     BEGIN
  663.     {$IFC qDebug}
  664.     IF gAskAboutAlloc & CanReadLn THEN
  665.         BEGIN
  666.  
  667.         GetCallersMethodName(s);
  668.         WriteLn('Within ', s, ', trying to make a ''', className, '''.');
  669.  
  670.         IF ReadYesNo('     Return NIL (Y or N) [N]? ') THEN
  671.             BEGIN
  672.             NewObjectByClassName := NIL;
  673.             EXIT(NewObjectByClassName);
  674.             END;
  675.         END;
  676.     {$ENDC qDebug}
  677.  
  678.     classID := GetClassIDFromName(className);
  679.     NewObjectByClassName := MakeNewInstance(classID);
  680.     END;
  681. {$Pop}
  682.  
  683. {--------------------------------------------------------------------------------------------------}
  684. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  685. {$S MAObjectRes}
  686.  
  687. PROCEDURE OBJFail(error: INTEGER);
  688.  
  689.     BEGIN
  690.     {$IFC qDebug}
  691.  
  692.     CASE error OF
  693.         kFailCoercion:
  694.             ProgramBreak('Object type coercion error.');
  695.         kFailMethNotFound:
  696.             ProgramBreak('Method not found');
  697.         OTHERWISE
  698.             BEGIN
  699.             WriteLn('Failure code: ', error);
  700.             ProgramBreak('Object runtime failure. See UObject.p.');
  701.             END;
  702.     END;
  703.     {$ENDC}
  704.     {$IFC qMacApp}
  705.     Failure(minErr, 0);                                 { ??? need to assign a message }
  706.     {$ELSEC}
  707.     { ??? Should we do anything if not for MacApp? }
  708.     {$ENDC}
  709.     END;
  710. {$Pop}
  711.  
  712. {--------------------------------------------------------------------------------------------------}
  713. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  714. {$W+}
  715. {$R-}
  716. {$OV-}
  717. {$S MAObjectRes}
  718.  
  719. PROCEDURE OrderClassIdsByName;
  720.  
  721.     VAR
  722.         startOfClassList, endOfClassList: IntegerPtr;
  723.         aClassName:         MAName;
  724.         nameFromTable:        MAName;
  725.         high, low, index:    INTEGER;
  726.         id:                 ObjClassId;
  727.         tableSize:            INTEGER;
  728.  
  729.     BEGIN
  730.     pNoOfOrderedClasses := 0;
  731.  
  732.  { pSuperClassTable is a handle to the combined superclass & classlist table.  The integer at
  733.  pSuperClassTable^^ gives the size of the superclass table. The classlist table immediately
  734.  follows the superclass table and the first integer in the classlist table gives the
  735.  size of the classlist table. }
  736.  
  737.     startOfClassList := IntegerPtr(ord(pSuperClassTable^) + IntegerHandle(pSuperClassTable)^^);
  738.     endOfClassList := IntegerPtr(ord(startOfClassList) + startOfClassList^);
  739.  
  740.     tableSize := ord(endOfClassList) - ord(startOfClassList);
  741.  
  742.     {$IFC qMacApp}                                        {We can't call failure if not for MacApp }
  743.     pOrderedClassIds := ClassIdTableHandle(NewPermHandle(tableSize));
  744.     FailNIL(pOrderedClassIds);
  745.     {$ELSEC}
  746.     pOrderedClassIds := ClassIdTableHandle(NewHandle(tableSize));
  747.     IF pOrderedClassIds = NIL THEN
  748.         EXIT(OrderClassIdsByName);                        { Caller should check for NIL }
  749.     {$ENDC}
  750.  
  751.     startOfClassList := IntegerPtr(ord(startOfClassList) + 2);
  752.     id := 2;
  753.     WHILE (ord(startOfClassList) < ord(endOfClassList)) DO
  754.         BEGIN
  755.         IF startOfClassList^ <> 0 THEN
  756.             BEGIN
  757.             GetClassNameFromID(ObjClassId(id), aClassName);
  758.  
  759.             IF pNoOfOrderedClasses = 0 THEN
  760.                 index := 1
  761.             ELSE
  762.                 BEGIN
  763.                 low := 1;
  764.                 high := pNoOfOrderedClasses;
  765.                 REPEAT
  766.                     index := BSR(low + high, 1);        { (low + high) DIV 2 }
  767.                     GetClassNameFromID(pOrderedClassIds^^[index], nameFromTable);
  768.                     IF aClassName < nameFromTable THEN
  769.                         high := index - 1
  770.                     ELSE
  771.                         BEGIN
  772.                         low := index + 1;
  773.                         index := index + 1;
  774.                         END;
  775.                 UNTIL low > high;
  776.  
  777.                 {$IFC qDebug}
  778.                 IF pNoOfOrderedClasses >= tableSize DIV 2 THEN
  779.                     ProgramBreak('Ordered class id table exceeded.');
  780.                 {$ENDC}
  781.                 END;
  782.             IF index <= pNoOfOrderedClasses THEN
  783.                 BlockMove(@pOrderedClassIds^^[index], @pOrderedClassIds^^[index + 1],
  784.                           (pNoOfOrderedClasses - index + 1) * sizeof(ObjClassId));
  785.             pOrderedClassIds^^[index] := id;
  786.             pNoOfOrderedClasses := pNoOfOrderedClasses + 1;
  787.             END;
  788.  
  789.         startOfClassList := IntegerPtr(ord(startOfClassList) + 2);
  790.         id := id + 2;
  791.         END;
  792.     END;
  793. {$Pop}
  794.  
  795. {--------------------------------------------------------------------------------------------------}
  796. {$S MADebug}
  797.  
  798. FUNCTION VerboseIsObject(obj: UNIV TObject): BOOLEAN;
  799.  
  800.     VAR
  801.         className:            MAName;
  802.         classSize:            Size;
  803.         instSize:            Size;
  804.  
  805.     BEGIN
  806.     VerboseIsObject := FALSE;
  807.     IF VerboseIsHandle(obj) THEN
  808.     { Test for handle not purged since we don't allow purgeable objects (??? yet?, ever?) }
  809.         IF (Ptr(StripLong(Handle(obj)^)) = NIL) THEN
  810.             WriteLn('  That handle appears to be purged.')
  811.         ELSE IF NOT IsClassIDMemberClass(ObjClassIDHandle(obj)^^, pTObjectClassID) THEN
  812.             WriteLn('  That handle is not a subclass of TObject.')
  813.         ELSE IF (GetHandleSize(Handle(obj)) < GetClassSizeFromId(GetClassID(obj))) THEN
  814.             BEGIN
  815.             GetClassNameFromID(GetClassID(obj), className);
  816.             classSize := GetClassSizeFromId(GetClassID(obj));
  817.             instSize := GetHandleSize(Handle(obj));
  818.             WriteLn('  That handle at: ', instSize: 1, ' bytes is smaller than a ', className,
  819.                     ' is supposed to be at: ', classSize: 1, ' bytes.');
  820.             END
  821.         ELSE
  822.             VerboseIsObject := TRUE;
  823.     END;
  824.  
  825. {--------------------------------------------------------------------------------------------------}
  826. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  827. {$S MADebug}
  828.  
  829. PROCEDURE WrLblField(fieldName: Str255;
  830.                      fieldAddr: Ptr;
  831.                      fieldType: INTEGER);
  832.  
  833.     BEGIN
  834.     pInspectLinePos := 0;
  835.     InspectField(fieldName, fieldAddr, fieldType);
  836.     pInspectLinePos := 0;
  837.     END;
  838. {$Pop}
  839.  
  840. {--------------------------------------------------------------------------------------------------}
  841. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  842. {$S %_MethTables}
  843.  
  844. PROCEDURE InstallDispatcher;
  845. { LOW LEVEL one time initialization. Must be in same segment as dispatcher. }
  846.  
  847.     TYPE
  848.         JmpToTrapPatchPtr    = ^JmpToTrapPatch;
  849.         JmpToTrapPatch        = RECORD
  850.             Jmp:                INTEGER;                { jmp instruction }
  851.             Routine:            ProcPtr;                { address to jump to }
  852.             END;
  853.  
  854.     VAR
  855.         aJmpToTrapPatchPtr: JmpToTrapPatchPtr;
  856.  
  857.     BEGIN
  858.     { The new method dispatcher provided with MacApp is enough faster that it is even worth using
  859.     instead of the ROM based dispatcher. }
  860.  
  861.     pMethDispAddr := @%_NewMethod;
  862.     {$IFC qDebug}
  863.     pODFail := @FailNonObject;
  864.     {$ENDC}
  865.  
  866. { NOTE =================================================
  867.  the following is a real slimedog trick but since we are
  868.  after performance in this bottleneck we'll do it anyway.
  869.  since it saves a memory fetch for each dispatch.
  870.  Don't need to flush the cache here.
  871.  }
  872.     aJmpToTrapPatchPtr := @%_JMPTOTRAP;
  873.     WITH aJmpToTrapPatchPtr^ DO
  874.         BEGIN
  875.         Jmp := $4EF9;                                    { JMP #Routine }
  876.         {$IFC qDebug}
  877.         Routine := @%_DISCIPLINEDISPATCH;
  878.         {$ELSEC}
  879.         Routine := pMethDispAddr;
  880.         {$ENDC}
  881.         END;
  882.  
  883.     {$IFC qDebug}
  884.     aJmpToTrapPatchPtr := @%_DISCIPLINEDISPATCH_PATCHPOINT;
  885.     WITH aJmpToTrapPatchPtr^ DO
  886.         BEGIN
  887.         Jmp := $4EF9;                                    { JMP #Routine }
  888.         Routine := pMethDispAddr;
  889.         END;
  890.     {$ENDC}
  891.  
  892.     { Don't forget the superclass table and the error handler }
  893.     pSuperClassTable := GetSuperClassTableHandle;
  894.     pDispatchErrorProc := @%_ObjError;
  895.  
  896.     END;
  897. {$Pop}
  898.  
  899. {--------------------------------------------------------------------------------------------------}
  900. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  901. {$S MAObjectRes}
  902.  
  903. PROCEDURE %_INITOBJ;
  904. { LOW LEVEL required to satisfy fussy linker.  Even though the optimizer
  905.  redirects these entry points they must at least be present. }
  906.  
  907.     BEGIN
  908.     END;
  909. {$Pop}
  910.  
  911. {--------------------------------------------------------------------------------------------------}
  912. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  913. {$S MAObjectRes}
  914.  
  915. PROCEDURE %_INOBJ;
  916. { LOW LEVEL required to satisfy fussy linker.  Even though the optimizer
  917.  redirects these entry points they must at least be present. }
  918.  
  919.     BEGIN
  920.     END;
  921. {$Pop}
  922.  
  923. {--------------------------------------------------------------------------------------------------}
  924. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  925. {$S MAObjectRes}
  926.  
  927. FUNCTION %_OBCHK(obj: TObject;
  928.                  jumpTablePtr: Ptr): TObject;
  929.  
  930. { LOW LEVEL routine called at run time verify object coercions.  It returns its obj
  931. parameter if the parameter is nil or passes the membership test.  Otherwise it calls
  932. ObjFail.  }
  933.  
  934.     BEGIN
  935.     {$IFC qDebug}
  936.     IF (obj <> NIL) THEN
  937.         FailNonObject(obj);
  938.     {$ENDC}
  939.     %_OBCHK := obj;
  940.     IF (obj <> NIL) & (NOT IsClassIDMemberClass(ObjClassIDHandle(obj)^^,
  941.                                                 ObjClassIDHandle(jumpTablePtr)^^)) THEN
  942.         OBJFail(kFailCoercion);
  943.     END;
  944. {$Pop}
  945.  
  946. {--------------------------------------------------------------------------------------------------}
  947. {$Push} {$Z+} {$IFC qTrace} {$D++} {$ENDC}
  948. {$S MAObjectRes}
  949.  
  950. PROCEDURE %_OBDISP(obj: TObject);
  951. { LOW LEVEL routine called by DISPOSE(<object>); }
  952.  
  953.     BEGIN
  954.     {$Ifc qDebug}
  955.     FailNonObject(obj);
  956.     {$Endc}
  957.  
  958.     {$IFC qInspector}
  959.     RemoveObjectFromInspector(obj);
  960.     {$ENDC}
  961.  
  962.     Handle(obj) := DisposeIfHandle(obj);
  963.     END;
  964. {$Pop}
  965.  
  966. {--------------------------------------------------------------------------------------------------}
  967.  
  968. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  969. {$S MAObjectRes}
  970.  
  971. PROCEDURE %_ObjError;
  972. { LOW LEVEL Error routine that ROM method dispatch routine jumps to if method not found
  973.   Address of this routine is stuffed at lomem location MAErrProc at startup }
  974.  
  975.     BEGIN
  976.     OBJFail(kFailMethNotFound);                         { Method Not Found }
  977.     END;
  978. {$Pop}
  979.  
  980. {--------------------------------------------------------------------------------------------------}
  981. {$Push} {$Z+} {$IFC qTrace} {$D++} {$ENDC}
  982.  
  983. {$S MAObjectRes}
  984.  
  985. PROCEDURE %_OBNEW(VAR obj: TObject;
  986.                   jumpTablePtr: Ptr;
  987.                   itsSize: INTEGER);                    { !!! itsSize is unused }
  988. { LOW LEVEL routine called by NEW(<object>); }
  989.  
  990.     VAR
  991.         {$IFC qDebug}
  992.         n:                    MAName;
  993.         s:                    MAName;
  994.         {$ENDC}
  995.         classID:            ObjClassId;
  996.  
  997.     BEGIN
  998.     classID := ObjClassIDHandle(jumpTablePtr)^^;
  999.     {$IFC qDebug}
  1000.     IF gAskAboutAlloc & CanReadLn THEN
  1001.         BEGIN
  1002.  
  1003.         GetCallersMethodName(s);
  1004.         GetClassNameFromID(classID, n);
  1005.         WriteLn('Within ', s, ', trying to make a ''', n, '''.');
  1006.  
  1007.         IF ReadYesNo('     Return NIL (Y or N) [N]? ') THEN
  1008.             BEGIN
  1009.             obj := NIL;
  1010.             EXIT(%_OBNEW);
  1011.             END;
  1012.         END;
  1013.     {$ENDC qDebug}
  1014.  
  1015.     obj := MakeNewInstance(classID);
  1016.     END;
  1017. {$Pop}
  1018.  
  1019. {--------------------------------------------------------------------------------------------------}
  1020. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  1021.  
  1022. {$S MAObjectRes}
  1023.  
  1024. FUNCTION %_OPTINOBJ(obj: TObject;
  1025.                     jumpTablePtr: Ptr): BOOLEAN;
  1026. { LOW LEVEL called to perform MEMBER function }
  1027.  
  1028.     BEGIN
  1029.     {$IFC qDebug}
  1030.     IF (obj <> NIL) THEN
  1031.         FailNonObject(obj);
  1032.     {$ENDC}
  1033.     %_OPTINOBJ := (obj <> NIL) & IsClassIDMemberClass(ObjClassIDHandle(obj)^^,
  1034.                                                       ObjClassIDHandle(jumpTablePtr)^^);
  1035.     END;
  1036. {$Pop}
  1037.  
  1038. {--------------------------------------------------------------------------------------------------}
  1039. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  1040. {$S MAObjectRes}
  1041.  
  1042. PROCEDURE %_OptInitObj;
  1043. { LOW LEVEL Not Used.  Must be present however to satisfy linker }
  1044.  
  1045.     BEGIN
  1046.     END;
  1047. {$Pop}
  1048.  
  1049. {--------------------------------------------------------------------------------------------------}
  1050. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  1051. {$S MAObjectRes}
  1052.  
  1053. PROCEDURE %_OptSetCI;
  1054. { LOW LEVEL Not Used.  Must be present however to satisfy linker }
  1055.  
  1056.     BEGIN
  1057.     END;
  1058. {$Pop}
  1059.  
  1060. {--------------------------------------------------------------------------------------------------}
  1061. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  1062. {$S MAObjectRes}
  1063.  
  1064. PROCEDURE %_METHOD;
  1065. { LOW LEVEL required to satisfy fussy linker.  Even though the optimizer
  1066.  redirects these entry points they must at least be present. }
  1067.  
  1068.     BEGIN
  1069.     END;
  1070. {$Pop}
  1071.  
  1072. {--------------------------------------------------------------------------------------------------}
  1073. {$Push} {$Z+} {$IFC qTrace} {$D+} {$ENDC}
  1074. {$S Main}                    { Must actually be in "Main" since it is called in UNIT setup by Pascal }
  1075.  
  1076. PROCEDURE %_PGM1;
  1077. { LOW LEVEL The Pascal compiler generates code to call this procedure automatically, before
  1078. initializing the units and starting the application's main program.  This function must always
  1079. work on 64K ROMs. }
  1080.  
  1081.     BEGIN
  1082.     END;
  1083. {$Pop}
  1084.  
  1085. {$Pop}
  1086.